package com.cms.html;

import com.cms.plugin.hook.HookServices;
import com.cms.common.hook.vo.HookParams;
import com.cms.common.hook.vo.HookResult;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Attribute;
import org.jsoup.nodes.Attributes;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.thymeleaf.context.Context;
import org.thymeleaf.spring5.SpringTemplateEngine;

import java.util.Map;

@Service
public class HtmlRenderService {


    @Autowired
    private SpringTemplateEngine templateEngine;


    public HtmlRenderService(SpringTemplateEngine templateEngine) {
        this.templateEngine = templateEngine;
    }


    // Render HTML using Thymeleaf template engine
    public String renderHtml(String templateName, Map<String, Object> variables, Context context) {
        if (context == null) {
            context = new Context();
        }

        // Set variables in context
        context.setVariables(variables);
        // Process template and get HTML
        String html = templateEngine.process(templateName, context);
        // Process layout and get HTML
        String htmlRs = TemplateEngineService.layoutProcess(html, variables, context);
        // Parse HTML
        Document doc = htmlRs != null ? Jsoup.parse(htmlRs) : Jsoup.parse(html);

        // Select all elements with hook attribute
        Elements hookWEles = doc.select("hook");
        if (!hookWEles.isEmpty()) {
            for (Element element : hookWEles) {
                // Get hook key
                String hook_key = element.attr("key");
                // Get child content
                String childContent = "";
                Elements childEles = element.children();
                for (Element childEle : childEles) {
                    if (childEle != null) {
                        childContent += childEle.toString();
                    }
                }

                // Create hook parameters
                HookParams hookParamHtmls = new HookParams();

                // Get attributes
                Attributes attributes = element.attributes();
                for (Attribute attribute : attributes) {
                    // Add attributes starting with data- to request parameters
                    if (attribute.getKey().startsWith("data-")) {
                        hookParamHtmls.getRequestParams().put(attribute.getKey(), attribute.getValue());
                    }
                }
                // Add child content to request parameters
                hookParamHtmls.getRequestParams().put("html", childContent);
                // Register hook
                HookResult hookResult = HookServices.regHook(hook_key, hookParamHtmls);
                // If hook fails, add child content after hook element and remove hook element
                if (hookResult.getCode() != 0) {
                    element.after(childContent);
                    element.remove();
                // If hook succeeds, add hook HTML after hook element and remove hook element
                } else {
                    String hookHtml = (String) hookParamHtmls.getRequestParams().get("html");
                    element.after(hookHtml);
                    element.remove();
                }

            }
        }

        // Return processed HTML
        return doc.toString();
    }


    // Insert content before element with given CSS query
    public String insertBefore(String html, String cssQuery, String content) {
        Document doc = Jsoup.parse(html);
        Element element = findEle(doc, cssQuery);
        if (element == null) {
            return html;
        }
        element.before(content);
        return doc.toString();
    }

    // Insert content after element with given CSS query
    public String insertAfter(String html, String cssQuery, String content) {
        Document doc = Jsoup.parse(html);
        Element element = findEle(doc, cssQuery);
        if (element == null) {
            return html;
        }
        element.after(content);
        return doc.toString();
    }


    // Replace content of element with given CSS query
    public String replaceContent(String html, String cssQuery, String content) {
        Document doc = Jsoup.parse(html);
        Element element = findEle(doc, cssQuery);
        if (element == null) {
            return html;
        }
        element.after(content);
        element.remove();
        return doc.toString();
    }

    // Find element with given CSS query
    private Element findEle(Document doc, String cssQuery) {
        Element element = doc.selectFirst(cssQuery);
        return element;
    }
}